package org.aseclipse.osgi.container;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Bundle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class ASBundle {
	private static final Log log_ = LogFactory.getLog(ASBundle.class);
	public static final String MANIFEST_NAME = "manifest_as.mf";
	public static final String PLUGIN_NAME = "plugin_as.xml";
	
	public static final String PLUGIN_ID = "id"; //$NON-NLS-1$
	public static final String EXTENSION_POINT = "extension-point"; //$NON-NLS-1$
	public static final String EXTENSION_POINT_NAME = "name"; //$NON-NLS-1$
	public static final String EXTENSION_POINT_ID = "id"; //$NON-NLS-1$
	public static final String EXTENSION_POINT_SCHEMA = "schema"; //$NON-NLS-1$

	public static final String EXTENSION = "extension"; //$NON-NLS-1$
	public static final String EXTENSION_NAME = "name"; //$NON-NLS-1$
	public static final String EXTENSION_ID = "id"; //$NON-NLS-1$
	public static final String EXTENSION_TARGET = "point"; //$NON-NLS-1$
	
	private Bundle parent_;
	private String name_;
	//private Properties manifest_;
	private byte[] manifest_;
	private byte[] pluginXML_;
	private List<String> points_;  // exposed extension points
	private List<String> extensions_;  // extension points which hosted by others, current bundle extends it
	private Map<String, byte[]> swcs_ = new HashMap<String, byte[]>();
	public ASBundle() {
	}
	
	public void init(Bundle bundle) throws IOException {
		parent_ = bundle;
		name_ = bundle.getSymbolicName();
		URL url = bundle.getResource(MANIFEST_NAME);
		if(url != null) {
			/*Properties pro = new Properties();
			byte[] buffer = BundleUtil.readURL(url);
			pro.load(new ByteArrayInputStream(buffer));
			manifest_ = pro;*/
			manifest_ = BundleUtil.readURL(url);
		}
		URL url2 = bundle.getResource(PLUGIN_NAME);
		if(url2 != null) {
			pluginXML_ = BundleUtil.readURL(url2);
			resolveExtensionPoints();
		}
	}
	
	public Bundle getBundle() {
		return parent_;
	}
	
	public String getName() {
		return name_;
	}
	/**
	 * @return extension points exposed
	 */
	public List<String> getPoints() {
		return points_;
	}
	
	/****
	 * @return point name list which extensions extend
	 */
	public List<String> getExtensions() {
		return extensions_;
	}
	
	public byte[] getManifest() {
		return manifest_;
	}
	
	public byte[] getPluginXML() {
		return pluginXML_;
	}
	
	public byte[] getLibrary(String key) {
		return swcs_.get(key);
	}
	
	public byte[] getResource(String resource) {
		if(swcs_.containsKey(resource)) {
			return swcs_.get(resource);
		} else {
			try {
				byte [] buffer = BundleUtil.readURL(parent_.getResource(resource));
				return buffer;
			} catch(Exception ex) {
				log_.warn("Don't contain '"+resource+ "' under bundle: "+getName());
				if(log_.isDebugEnabled())
					log_.debug("", ex);
			}
		}
		return null;
	}
	
	private void resolveExtensionPoints() {
		try {
			Document doc = BundleUtil.parse(pluginXML_);
			Element root = doc.getDocumentElement();
			String id = root.getAttribute(PLUGIN_ID);
			NodeList list = root.getChildNodes();
			for(int i=0; i<list.getLength(); i++) {
				Node node = list.item(i);
				if(node instanceof Element) {
					Element element = (Element)node;
					if(node.getNodeName().equals(EXTENSION_POINT)) {
						String pointId = element.getAttribute(EXTENSION_POINT_ID);
						if(points_ == null) {
							points_ = new ArrayList<String>();
						}
						points_.add(id + "." + pointId);
					} else if(node.getNodeName().equals(EXTENSION)) {
						String pointId = element.getAttribute(EXTENSION_TARGET);
						if(extensions_ == null) {
							extensions_ = new ArrayList<String>();
						}
						extensions_.add(pointId);
					}
				}
			}
			if(log_.isDebugEnabled()) {
				if(points_ != null)
					log_.debug("[ExtensinPoint] " + BundleUtil.join(points_, ", "));
				if(extensions_ != null)
					log_.debug("[Extensins] " + BundleUtil.join(extensions_, ", "));
			}
		}catch(Exception ex) {
			log_.warn("", ex);
		}
	}
	
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(">>> Bundle "+parent_.getSymbolicName() +"\n");
		buffer.append("Header: " + (manifest_ == null ? ("") : new String(manifest_)));
		buffer.append("Plugin: " + (pluginXML_ == null ? ("") : new String(pluginXML_)));
		buffer.append("<<< Bundle");
		return buffer.toString();
	}
}
